#include "SawBot.h"
#include "GamePlayState.h"
#include "Game.h"
#include "DestroyEntityMessage.h"
#include "SaviorPart.h"
#include "BotFloorSaw.h"
#include "EventSystem.h"
#include "CreateProjectileMessage.h"
#include "SGD Wrappers\CSGD_Direct3D.h"
#include "SGD Wrappers\CSGD_XAudio2.h"
#include "CutsceneState.h"

SawBot::SawBot(Player* p1, Player* p2)
{
	type = OBJ_ENEMY;
	SetHealth(500.0f);
	SetMaxHealth(500.0f);
	SetDifficulty(1);
	SetWidth(256);
	SetHeight(128);
	SetSpeed(32);
	SetDirection(2);

	player1 = p1;
	player2 = p2;

	p2 == nullptr ? twoPlayer = false : twoPlayer = true;

	state = 0;
	damage = 10;
	oneFrame = false;

	attackTimer = 0;
	attackRate = 3.0f;
	waitTime = 0.5f;
	floorsawTimer = 0;

	target = 0;
	targetPosX = 0;
	targetPosY = 0;

	EventSystem::GetInstance()->RegisterClient("target_hit", this);

	moveSound		= CSGD_XAudio2::GetInstance()->SFXLoadSound(_T("Sound/SawBot_Move.wav"));
	attackSound		= CSGD_XAudio2::GetInstance()->SFXLoadSound(_T("Sound/SawBot_Attack.wav"));;
	shootSound		= CSGD_XAudio2::GetInstance()->SFXLoadSound(_T("Sound/SawBot_Shoot.wav"));;
	floorSawSound	= CSGD_XAudio2::GetInstance()->SFXLoadSound(_T("Sound/Melee Weapons/sawAttack.wav"));;
	hurtSound		= CSGD_XAudio2::GetInstance()->SFXLoadSound(_T("Sound/SawBot_Hurt.wav"));;
}

SawBot::~SawBot()
{
	if( moveSound != -1 )
	{
		CSGD_XAudio2::GetInstance()->SFXStopSound(moveSound);
		CSGD_XAudio2::GetInstance()->SFXUnloadSound(moveSound);
		moveSound = -1;
	}
	if( attackSound != -1 )
	{
		CSGD_XAudio2::GetInstance()->SFXStopSound(attackSound);
		CSGD_XAudio2::GetInstance()->SFXUnloadSound(attackSound);
		attackSound = -1;
	}
	if( shootSound != -1 )
	{
		CSGD_XAudio2::GetInstance()->SFXStopSound(shootSound);
		CSGD_XAudio2::GetInstance()->SFXUnloadSound(shootSound);
		shootSound = -1;
	}
	if( floorSawSound != -1 )
	{
		CSGD_XAudio2::GetInstance()->SFXStopSound(floorSawSound);
		CSGD_XAudio2::GetInstance()->SFXUnloadSound(floorSawSound);
		floorSawSound = -1;
	}
	if( hurtSound != -1 )
	{
		CSGD_XAudio2::GetInstance()->SFXStopSound(hurtSound);
		CSGD_XAudio2::GetInstance()->SFXUnloadSound(hurtSound);
		hurtSound = -1;
	}
	EventSystem::GetInstance()->UnregisterClientAll(this);
}

void SawBot::Update(float elapsed)
{
	if(player1->GetRoomNum() != GetRoomNum())
		return;

	if(GetHealth() <= 0)
	{
		// Give the players resources
		if(twoPlayer)
		{
			player2->SetMetal(player2->GetMetal() + 50);
			player2->SetCircuitry(player2->GetCircuitry() + 50);
			player1->SetMetal(player1->GetMetal() + 50);
			player1->SetCircuitry(player1->GetCircuitry() + 50);
		}
		else
		{
			player1->SetMetal(player1->GetMetal() + 100);
			player1->SetCircuitry(player1->GetCircuitry() + 100);
		}

		DestroyEntityMessage* msg = new DestroyEntityMessage(this);
		MessageSystem::GetInstance()->SendMsg(msg);
		msg = nullptr;

		GamePlayState::GetInstance()->inCutscene = true;
		CutsceneState::GetInstance()->RunCutscene(CutsceneState::SCENE_GAMECOMPLETE);

		return;
	}

	Enemy::Update(elapsed);

	if(disabled == true)
		return;

	if(player1->GetX() > GetX() + GetWidth())
	{
		if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(moveSound))
			CSGD_XAudio2::GetInstance()->SFXPlaySound(moveSound);

		SetX(GetX() + GetSpeed() * elapsed);
	}
	else if(player1->GetX() + player1->GetWidth() < GetX())
	{
		if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(moveSound))
			CSGD_XAudio2::GetInstance()->SFXPlaySound(moveSound);

		SetX(GetX() - GetSpeed() * elapsed);
	}

	if(GetHealth() / GetMaxHealth() <= 0.33f)
	{
		state = 3;
		attackRate = 2.0f;
		SetSpeed(64);
	}
	else if(GetHealth() / GetMaxHealth() <= 0.66f)
	{
		state = 2;
		attackRate = 2.5f;
		SetSpeed(48);
	}

	attackTimer += elapsed;
	if(attackTimer >= attackRate)
	{
		oneFrame = true;
		Attack(elapsed);
	}

	sawBot[state].Update(elapsed);
}

void SawBot::Render()
{
	int camx = GamePlayState::GetInstance()->GetCamX();
	int camy = GamePlayState::GetInstance()->GetCamY();
	if( GetX() > camx + 800 || GetX() + GetWidth() < camx || GetY() + GetHeight() < camy || GetY() > camy + 600 )
	{
		return;
	}

	DWORD color;

	switch(state)
	{
	case 0:
		color = D3DCOLOR_ARGB(255,0,255,0);
		break;

	case 1:
		color = D3DCOLOR_ARGB(255,0,255,0);
		break;

	case 2:
		color = D3DCOLOR_ARGB(255,127,127,0);
		break;

	case 3:
		color = D3DCOLOR_ARGB(255,255,0,0);
		break;

	}
	
	sawBot[state].Render((int)GetX()- GamePlayState::GetInstance()->GetCamX(),
		(int)GetY()- GamePlayState::GetInstance()->GetCamY(),1.0f,color,false);

	if(state == 3)
	{
		CSGD_Direct3D::GetInstance()->GetSprite()->Flush();

		RECT rect;
		rect.top = targetPosY - GamePlayState::GetInstance()->GetCamY();
		rect.bottom = rect.top + 32;
		rect.left = targetPosX - GamePlayState::GetInstance()->GetCamX();
		rect.right = rect.left + 32;

		CSGD_Direct3D::GetInstance()->DrawRect(rect, 255, 0, 0);
	}

}

bool SawBot::CheckCollision(IEntity* base)
{
	if(oneFrame == false)
		return false;

	if(Entity::CheckCollision(base) == true && base != this && base->GetType() != OBJ_ENEMY)
	{
		if(base->GetType() == OBJ_PLAYER)
		{
			oneFrame = false;
			EventSystem::GetInstance()->SendEvent("player_hit", base, new float(damage),
				new int(dynamic_cast<Player*>(base)->GetPlayerNum()));
			return true;
		}
	}
	return false;
}

void SawBot::Attack(float elapsed)
{
	switch(state)
	{
	case 0:
		{
			if(player1->GetY() <= GetY() + GetHeight() && player1->GetY() + player1->GetHeight() >= GetY())
			{
				if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(attackSound))
					CSGD_XAudio2::GetInstance()->SFXPlaySound(attackSound);
				state = 1;
				sawBot[state].Play();
				attackTimer = 0;
			}
			else if(player1->GetX() <= GetX() + GetWidth() && player1->GetX() + player1->GetWidth() >= GetX())
			{
				if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(attackSound))
					CSGD_XAudio2::GetInstance()->SFXPlaySound(attackSound);
				state = 0;
				sawBot[state].Play();
				attackTimer = 0;
			}

			if(twoPlayer)
			{
				if(player2->GetY() <= GetY() + GetHeight() && player2->GetY() + player2->GetHeight() >= GetY())
				{
					if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(attackSound))
						CSGD_XAudio2::GetInstance()->SFXPlaySound(attackSound);
					state = 1;
					sawBot[state].Play();
					attackTimer = 0;
				}
				else if(player2->GetX() <= GetX() + GetWidth() && player2->GetX() + player2->GetWidth() >= GetX())
				{
					if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(attackSound))
						CSGD_XAudio2::GetInstance()->SFXPlaySound(attackSound);
					state = 0;
					sawBot[state].Play();
					attackTimer = 0;
				}
			}
		}
		break;

	case 1:
		{
			if(player1->GetY() <= GetY() + GetHeight() && player1->GetY() + player1->GetHeight() >= GetY())
			{
				if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(attackSound))
					CSGD_XAudio2::GetInstance()->SFXPlaySound(attackSound);
				state = 1;
				sawBot[1].Play();
				attackTimer = 0;
			}
			else if(player1->GetX() <= GetX() + GetWidth() && player1->GetX() + player1->GetWidth() >= GetX())
			{
				if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(attackSound))
					CSGD_XAudio2::GetInstance()->SFXPlaySound(attackSound);
				state = 0;
				sawBot[0].Play();
				attackTimer = 0;
			}

			if(twoPlayer)
			{
				if(player2->GetY() <= GetY() + GetHeight() && player2->GetY() + player2->GetHeight() >= GetY())
				{
					if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(attackSound))
						CSGD_XAudio2::GetInstance()->SFXPlaySound(attackSound);
					state = 1;
					sawBot[1].Play();
					attackTimer = 0;
				}
				else if(player2->GetX() <= GetX() + GetWidth() && player2->GetX() + player2->GetWidth() >= GetX())
				{
					if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(attackSound))
						CSGD_XAudio2::GetInstance()->SFXPlaySound(attackSound);
					state = 0;
					sawBot[0].Play();
					attackTimer = 0;
				}
			}
		}
		break;

	case 2:
		{
			if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(shootSound))
				CSGD_XAudio2::GetInstance()->SFXPlaySound(shootSound);
			sawBot[state].Play();
			CreateProjectileMessage* msg = new CreateProjectileMessage(SAWBOT, this);
			MessageSystem::GetInstance()->SendMsg(msg);
			msg = nullptr;
			attackTimer = 0;
		}
		break;

	case 3:
		{
			if(floorsawTimer == 0)
			{
				sawBot[state].Play();
				twoPlayer ? target = rand()%2 : target = 0;

				if(target == 0)
				{
					targetPosX = (int)player1->GetX();
					targetPosY = (int)player1->GetY();
				}
				else
				{
					targetPosX = (int)player2->GetX();
					targetPosY = (int)player2->GetY();
				}
			}

			if(sawBot[state].GetCurFrame() == 3)
				sawBot[state].Stop();

			if(floorsawTimer >= waitTime)
			{
				if(!CSGD_XAudio2::GetInstance()->SFXIsSoundPlaying(floorSawSound))
					CSGD_XAudio2::GetInstance()->SFXPlaySound(floorSawSound);

				Hazard* h = nullptr;
				h = new BotFloorSaw();
				h->SetX((float)targetPosX);
				h->SetY((float)targetPosY);
				h->SetRoomNumber(GetRoomNum());

				ObjectManager::GetInstance()->AddObject(h);

				floorsawTimer = 0;
				attackTimer = 0;
			}
			else
				floorsawTimer += elapsed;
		}
		break;
	}
}

void SawBot::HandleEvent(Event* thisEvent)
{
	if(thisEvent->GetParameter() != this)
		return;

	if(thisEvent->GetEventID() == "target_hit" && GetHealth() > 0)
	{
		SetHealth(GetHealth() - *((float*)(thisEvent->GetParameter2())));

		CSGD_XAudio2::GetInstance()->SFXPlaySound(hurtSound);
	}
}

RECT SawBot::GetRect()
{
	RECT tmp = sawBot[state].GetCollsionRect();

	int width = tmp.right;
	int height = tmp.bottom;
	tmp.top += (long)(GetY() - sawBot[state].GetAPoint().fY + height);
	tmp.bottom = height + tmp.top;
	tmp.left += (long)(GetX() - sawBot[state].GetAPoint().fX + (width/2));
	tmp.right = width + tmp.left;

	return tmp;
}
